package org.jeecg.modules.third.nucarf;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.third.nucarf.dto.BaseResult;
import org.jeecg.modules.third.nucarf.dto.CUInfo;
import org.jeecg.modules.third.nucarf.dto.NucartResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.net.ssl.*;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;

@Service
@Slf4j
public class NucartUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(NucartUtils.class);

    @Value(value="${gas.baseUrl}")
    private String baseUrl;

    public NucartUtils(){

    }

    public NucartUtils(String baseUrl){
        this.baseUrl = baseUrl;
    }
    /**
     * 连接接口
     * @param url 请求接口
     * @param map  post参数
     */
    public static String invoke(String url, Map map , String appid , String secret) throws Exception{
        //获取到加密的签名
        String sign = getSign(map ,secret );
        //拼接请求路径
        String http_url = url + "?sign=" + sign + "&appid=" + appid;
        URL urlObject = new URL(http_url);
        // 打开和URL之间的连接
        trustAllHttpsCertificates();
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
//                System.out.println("Warning: URL Host: " + urlHostName + " vs. " + session.getPeerHost());
                return true;
            }
        };
        HttpsURLConnection.setDefaultHostnameVerifier(hv);

        //测试环境连接
        HttpURLConnection conn = (HttpURLConnection) urlObject.openConnection();
        if(url.contains("https")){
            conn = (HttpsURLConnection) urlObject.openConnection();
        }

        //设置post请求
        conn.setRequestMethod("POST");
        conn.setUseCaches(false);//设置不要缓存
        conn.setInstanceFollowRedirects(true);
        //设置是否向connection输出，因为这个是post请求，参数要放在http正文内，因此需要设为true,默认情况下是false
        conn.setDoOutput(true);
        //设置是否从connection读入，默认情况下是true;
        conn.setDoInput(true);
        //建立TCP连接,getOutputStream会隐含的进行connect,所以此处可以不要
        conn.connect();
        // 创建输入输出流,用于往连接里面输出携带的参数
        DataOutputStream out = null;
        if(map!=null&&map.size()>0) {
            out = new DataOutputStream(conn.getOutputStream());
            String param = getParam(map);
            int length = 0;
            int totalLength = param.length();

            while(length < totalLength) {
                int endLength = length + 1024;
                if (endLength > totalLength) {
                    endLength = totalLength;
                }
                out.write(param.substring(length, endLength).getBytes("UTF-8"));
                length = endLength;
                out.flush();
            }
            out.close();
        }
        BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        String lines="";
        StringBuffer result = new StringBuffer("");
        // 循环读取流
        while ((lines = reader.readLine()) != null) {
//            lines = new String(lines.getBytes(), "utf-8");
            lines = new String(lines.getBytes(), "utf-8");
            result.append(lines);
        }
        reader.close();
        conn.disconnect();
        return result.toString();
    }

    /**
     * 获取加密的签名
     * @return 返回加密后的签名
     */
    private static String getSign(Map mapParam, String secret){
        //获取秒级的时间戳
        long time=new Date().getTime()/1000;
        int rnum=(int)(Math.random()*100000);
        //加密sign签名 所需要的参数
        Map<String,Object> map=new HashMap<>();
        map.put("api_random_number",rnum);
        map.put("api_time_stamp",time);
        map.putAll(mapParam);
        //对参数进行排序
        String sign=sort(map , secret);
//        System.out.println(sign);
        //返回加密后的签名
        return md5(getSha1(sign))+"_"+time+"_"+rnum;
    }
    /**
     * 获取加密的签名
     * @return 返回加密后的签名
     */
    public static String getSign2(String secret){
        //获取秒级的时间戳
        long time=new Date().getTime()/1000;
        int rnum=(int)(Math.random()*100000);
        //加密sign签名 所需要的参数
        Map<String,Object> map=new HashMap<>();
        map.put("api_random_number",rnum);
        map.put("api_time_stamp",time);
        //对参数进行排序
        String sign=sort(map , secret);
//        System.out.println(sign);
        //返回加密后的签名
        return md5(getSha1(sign))+"_"+time+"_"+rnum;
    }
    /**
     * sha1加密
     * @param decript 需要加密的字符串
     * @return 加密后的字符串
     */
    private static String getSha1(String decript){
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-1");
            digest.update(decript.getBytes("UTF-8"));
            byte messageDigest[] = digest.digest();
            // Create Hex String
            StringBuffer hexString = new StringBuffer();
            for (int i = 0; i < messageDigest.length; i++)
                hexString.append(String.format("%02X", 0xFF & messageDigest[i]));
            return   hexString.toString().toLowerCase();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * MD5加密
     * @param str 需要加密的字符串
     * @return 加密后的字符串
     */
    private static String md5(String str) {
        //创建MD5加密对象
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        // 进行加密
        md5.update(str.getBytes());
        //获取加密后的字节数组
        byte[] md5Bytes = md5.digest();
        String res = "";
        for (int i = 0; i < md5Bytes.length; i++) {
            int temp = md5Bytes[i] & 0xFF;
            // 转化成十六进制不够两位，前面加零
            if (temp <= 0XF) {
                res += "0";
            }
            res += Integer.toHexString(temp);
        }
        return new String(res.getBytes(), 0, res.getBytes().length);
    }
    private static String getParam(Map map){
        StringBuffer buffer = new StringBuffer(200);
        if (map != null && !map.isEmpty()) {
            Iterator var4 = map.entrySet().iterator();

            while(var4.hasNext()) {
                Map.Entry<String, String> entry = (Map.Entry)var4.next();
                buffer.append((String)entry.getKey()).append("=").append((String)entry.getValue()).append("&");
            }

            buffer.deleteCharAt(buffer.length() - 1);
        }

        return buffer.toString();
    }

    /**
     * 将参数排序并拼接成字符串 返回
     * @param objectMap 参数map
     * @param secret
     * @return 按规则拼接好的字符串
     */
    private static String sort(Map<String, Object> objectMap, String secret){
        if(objectMap==null||objectMap.isEmpty()){
            return "";
        }
        Set<String> set=objectMap.keySet();
        Object[] strs= set.toArray();
        Arrays.sort(strs);
        String resultStr="";
        for(int j=0;j<strs.length;j++){
            resultStr+="&"+strs[j]+"="+objectMap.get(strs[j]);
        }
        resultStr="secret="+secret+resultStr;
        return resultStr;
    }
    private static void trustAllHttpsCertificates() throws Exception {
        TrustManager[] trustAllCerts = new TrustManager[1];
        TrustManager tm = new miTM();
        trustAllCerts[0] = tm;
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init((KeyManager[])null, trustAllCerts, (SecureRandom)null);
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }

    static class miTM implements TrustManager, X509TrustManager {
        miTM() {
        }

        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public boolean isServerTrusted(X509Certificate[] certs) {
            return true;
        }

        public boolean isClientTrusted(X509Certificate[] certs) {
            return true;
        }

        public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
        }

        public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
        }
    }

    public  NucartResult<?> createUser(String name , String username , String idcard , String car_no  , String money ,String appid ,String secret,
                                       String sname, String ename, String remark,String shippingNoteNum,String vehicleEnergyType
    ) {
        try {
            //post请求参数
            Map map = new HashMap();
            map.put("name", name);
            map.put("username", username);
            map.put("user_code", idcard);
            map.put("car_no", car_no);
            map.put("category", vehicleEnergyType.equals("E") ? "2" : "1");
            map.put("money", money);
            map.put("sname", sname);
            map.put("ename", ename);
            map.put("remark", remark);
//            map.put("u_flow_number", shippingNoteNum);
            map.put("foreign_ordersn", shippingNoteNum);

            String url = baseUrl + "/PublicApi/CompanyGroup/createApiMember";
            //String url = baseUrl + "/PublicApi/MemberCart/createUser";
            String result = invoke(url, map, appid, secret);
//            LOGGER.info("NucartUtils createUser map :{},result:{}" , JSONObject.toJSONString(map),result);
            NucartResult r = JSON.parseObject(result, new TypeReference<NucartResult<CUInfo>>() {});
            return r;
        } catch (Exception e) {
            return NucartResult.error(e.getMessage());
        }
    }
    //查询余额
    public  NucartResult<?> getBackMoney(String username ,String appid ,String secret) {
        try {
            //post请求参数
            Map map = new HashMap();
            map.put("username", username);

            String url = baseUrl + "/PublicApi/GroupMember/byUsernameGetBackMoney";
            //String url = baseUrl + "/PublicApi/MemberCart/byUsernameGetBackMoney";
            String result = invoke(url, map, appid, secret);
            NucartResult r = JSON.parseObject(result, new TypeReference<NucartResult<CUInfo>>() {});
            return r;
        } catch (Exception e) {
            return NucartResult.error(e.getMessage());
        }
    }

    //回收司机余额
    public  NucartResult<?> backMoney(String username ,String money,String appid ,String secret
            ,String vehicleEnergyType
    ) {
        try {
            //post请求参数
            Map map = new HashMap();
            map.put("username", username);
            map.put("money", money);
            map.put("category", vehicleEnergyType.equals("E") ? "2" : "1");
            String url = baseUrl + "/PublicApi/CompanyGroup/backMoneyByUsername";
            //String url = baseUrl + "/PublicApi/MemberCart/byUsernameBackMoney";
            String result = invoke(url, map, appid, secret);
//            LOGGER.info("NucartUtils backMoney map :{},result:{}" , JSONObject.toJSONString(map),result);
            NucartResult r = JSON.parseObject(result, new TypeReference<NucartResult<CUInfo>>() {});
            return r;
        } catch (Exception e) {
            return NucartResult.error(e.getMessage());
        }
    }

    /**
     * 0旧账户、1柴油+天然气、2柴油、3天然气、4非能源、5汽油、6柴油+非能源
     * 企业账户余额查询
     * @param appid
     * @param secret
     * @return
     */
    public  NucartResult<?> getCompanyMoney(String appid ,String secret) {
        try {
            //post请求参数
            Map map = new HashMap();

            String url = baseUrl + "/PublicApi/CompanyGroup/getCompanyMoneyByCategory";
           // String url = baseUrl + "/PublicApi/Company/balance";
            String result = invoke(url, map, appid, secret);
            log.info("万金油企业账户余额查询 {} -> {}" ,url, result);
            NucartResult r = JSON.parseObject(result, new TypeReference<NucartResult<BaseResult>>() {});
            return r;
        } catch (Exception e) {
            return NucartResult.error(e.getMessage());
        }
    }

    public static void main(String[] args) throws Exception {
        /*Map map = new HashMap();
        map.put("username", "18713969333");
        String url = "http://vip.nucarf.net/" + "PublicApi/MemberCart/authMember";
        String result = GETinvoke(url, map, "052292fe1ea676c06f7b62ffafe5f4b4", "c1cee901f6a9036d947c2b07c6fd62f3","18713969333");
        NucartResult r = JSON.parseObject(result, new TypeReference<NucartResult<BaseResult>>() {});
        System.out.println(r);*/
//        String url = "http://vip.nucarf.net/" + "PublicApi/MemberCart/authMember";
//        String sign = getSign2("c1cee901f6a9036d947c2b07c6fd62f3");
//        //拼接请求路径
//        String http_url = url + "?sign=" + sign + "&appid=" + "052292fe1ea676c06f7b62ffafe5f4b4" + "&username=" + "18713969333";
//        System.out.println(111);
//        String s = HttpURLConnectionUtil.doGet(http_url);
//        System.out.println(s);
//        System.out.println(s);


        Map map = new HashMap();
        map.put("username", "18132180605");
        String url = "http://tvip.nucarf.cn/PublicApi/GroupMember/byUsernameGetBackMoney";
        String result = invoke(url, map, "ba2ffcc00c2cc7c9d8cca22ff8d8561d", "3c0082d26f0d2e3dd358767f5421f387");
        NucartResult r = JSON.parseObject(result, new TypeReference<NucartResult<String>>() {});
    }

}
